package com.coderman.common.starter.idempotent.aspect;

import com.coderman.common.starter.idempotent.Constant;
import com.coderman.common.starter.idempotent.annotations.RedisLock;
import com.coderman.common.starter.idempotent.service.DistributedLocker;
import com.coderman.common.starter.idempotent.service.LockService;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.CodeSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

@Aspect
@Component
@Order(value = 3)
public class RedisLockAspect {
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Value("{spring.application.ame}")
    private String serviceName;


    @Autowired
    private LockService lockService;

    @Pointcut("@annotation(com.coderman.common.starter.idempotent.annotations.RedisLock)")
    public void idemPotentiPointCut() {

    }

    @Transactional(rollbackFor = Exception.class)
    @Around("@annotation(idemPotent)")
    public Object aroundIdemPotent(ProceedingJoinPoint joinPoint, RedisLock idemPotent) throws Throwable {
        Object[] paramValues = joinPoint.getArgs();
        String[] paramNames = ((CodeSignature) joinPoint.getSignature()).getParameterNames();
        List<String> keyList = new ArrayList<>();
        String[] fieldArr = idemPotent.fieldArr();
        /**
         * 适用于防重复提交
         * 唯一业务
         */
        String key = "";
        if (fieldArr.length == 0 || fieldArr[0].equals("")) {
            key = getKey(idemPotent.prefixKey());
        } else {
            keyList = KeyBuilder.getKeyList(paramValues, paramNames, fieldArr);
            if (keyList.size() == 0) {
                keyList = KeyBuilder.getKeyListFromObject(paramValues, fieldArr);
            }
            String[] keyarr = new String[keyList.size()];
            keyList.toArray(keyarr);
            key = getKey(idemPotent.prefixKey(), keyarr);
        }

        //防止重复提交
        if (idemPotent.funcType() == 0 || idemPotent.funcType() == 2) {
            boolean b = lockService.getDistributedLocker().lock(key, idemPotent.timeout());
            //加锁失败
            if(!b){

            }
        }
        //幂等
        else if (idemPotent.funcType() == 1) {
            key = getKey(idemPotent.prefixKey());

        }
        //3:唯一性校验
        else if (idemPotent.funcType() == 3) {
            key = getKey(idemPotent.prefixKey());
            StringBuilder value = new StringBuilder();
            keyList.forEach(v->{
                value.append(v+"-");
            });

        }


        return joinPoint.proceed();
    }

    /**
     * @param prefix
     * @param keyList
     * @return
     */
    private String getKey(String prefix, String... keyList) {
        String basicKey = serviceName + "_" + Constant.NO_REPEAT_PRE + prefix + "_";

        if (keyList == null || keyList.length == 0) {
            return basicKey;
        }
        if (keyList.length > 2) {
            logger.error("key params too much.......");
        }

        if (keyList.length == 1) {
            basicKey = basicKey + keyList[0];
        } else {
            basicKey = basicKey + keyList[0] + "_" + keyList[1];
        }
        return basicKey;
    }


    /**
     * 校验基本类型
     *
     * @param typeName typeName
     * @return boolean
     */
    private static Class checkPrimitive(String typeName) {
        if (typeName.equals("java.lang.String")) {
            return String.class;
        }
        if (typeName.equals("java.lang.Boolean")) {
            return Boolean.class;
        }
        if (typeName.equals("java.lang.Character")) {
            return Character.class;
        }
        if (typeName.equals("java.lang.Byte")) {
            return Byte.class;
        }
        if (typeName.equals("java.lang.Short")) {
            return Short.class;
        }
        if (typeName.equals("java.lang.Integer")) {
            return Integer.class;
        }
        if (typeName.equals("java.lang.Long")) {
            return Long.class;
        }
        if (typeName.equals("java.lang.Float")) {
            return Float.class;
        }
        if (typeName.equals("java.lang.Double")) {
            return Double.class;
        }
        return null;
    }

}
